package com.cj.library.widget.view;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.View;

import com.cj.library.widget.R;

/**
 * Created by JiangGe on 2016/9/6.
 */
public class TimerView extends View {

    /**
     * Circle
     */
    public static final int CLASS_STYLE_CIRCLE = 0;
    /**
     * digit
     */
    public static final int CLASS_STYLE_DIGIT = 1;
    /**
     * clock
     */
    public static final int CLASS_STYLE_CLOCK = 2;

    /**
     * Circle and digit
     */
    public static final int CLASS_STYLE_CIRCLE_DIGIT = 3;

    /**
     * clock and digit
     */
    public static final int CLASS_STYLE_CLOCK_DIGIT = 4;

    public static final int CLASS_STYLE_CLOCK_CLEAR = 5;
    public static final int CLASS_STYLE_CIRCLE_CLEAR = 6;

    private boolean isStart;//是否开始计时
    private OnTimerListener onTimerListener;

    private int backGroundColor = Color.WHITE;

    //CLASS_STYLE_CIRCLE
    private int classStyle;
    private int maxCount = 30;
    private int current;
    private float circleWidth;
    private int progressColor;
    private int backColor;
    private Paint circlePaint;
    private RectF circleRectf;

    //CLASS_STYLE_DIGIT
    private String unitStr;//默认单位
    private Paint digitPaint;
    private float digitSize;
    private String tipStr;

    //CLASS_STYLE_CLOCK
    private Paint clockPaint;
    private float clockWidth;
    private float clockLength;
    private int clockDefaultColor;
    private int clockProgressColor;

    public TimerView(Context context) {
        this(context, null);
    }

    public TimerView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public TimerView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        if (attrs != null) {
            TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TimerView);
            classStyle = a.getInt(R.styleable.TimerView_timer_class_style, CLASS_STYLE_CIRCLE);
            maxCount = a.getInt(R.styleable.TimerView_maxCount, 60);
            backGroundColor = a.getColor(R.styleable.TimerView_timer_backGroundColor, Color.WHITE);
            switch (classStyle) {
                case CLASS_STYLE_CIRCLE:
                case CLASS_STYLE_CIRCLE_CLEAR:
                    initCircle(a);
                    break;
                case CLASS_STYLE_DIGIT:
                    initDigit(a);
                    break;
                case CLASS_STYLE_CLOCK:
                case CLASS_STYLE_CLOCK_CLEAR:
                    initClock(a);
                    break;
                case CLASS_STYLE_CIRCLE_DIGIT:
                    initCircle(a);
                    initDigit(a);
                    break;
                case CLASS_STYLE_CLOCK_DIGIT:
                    initClock(a);
                    initDigit(a);
                    break;
            }
            a.recycle();
        }


    }

    private void initClock(TypedArray a) {
        clockPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        clockWidth = a.getDimension(R.styleable.TimerView_clockWidth, 10);
        clockPaint.setStrokeWidth(clockWidth);
        clockLength = a.getDimension(R.styleable.TimerView_clockLength, 20);
        clockProgressColor = a.getColor(R.styleable.TimerView_clockProgressColor, Color.RED);
        clockDefaultColor = a.getColor(R.styleable.TimerView_clockDefaultColor, Color.BLACK);
    }

    private void initDigit(TypedArray a) {
        digitPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        unitStr = a.getString(R.styleable.TimerView_unitStr);
        tipStr = a.getString(R.styleable.TimerView_tipStr);
        if (tipStr == null) {
            tipStr = "";
        }

        digitSize = a.getDimension(R.styleable.TimerView_digitSize, 18);
        digitPaint.setTextSize(digitSize);
        if (unitStr == null) {
            unitStr = "";
        }
    }

    private void initCircle(TypedArray a) {
        circleWidth = a.getDimension(R.styleable.TimerView_circleWidth, 0);
        circlePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        circlePaint.setStrokeWidth(circleWidth);
        progressColor = a.getColor(R.styleable.TimerView_progressColor, Color.RED);
        backColor = a.getColor(R.styleable.TimerView_backColor, Color.BLACK);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawColor(backGroundColor);
        switch (classStyle) {
            case CLASS_STYLE_CIRCLE:
            case CLASS_STYLE_CIRCLE_CLEAR:
                drawCircle(canvas);
                break;
            case CLASS_STYLE_DIGIT:
                drawDigit(canvas);
                break;
            case CLASS_STYLE_CLOCK_CLEAR:
            case CLASS_STYLE_CLOCK:
                drawClock(canvas);
                break;
            case CLASS_STYLE_CIRCLE_DIGIT:
                drawCircle(canvas);
                drawDigit(canvas);
                break;
            case CLASS_STYLE_CLOCK_DIGIT:
                drawClock(canvas);
                drawDigit(canvas);
                break;
        }
    }

    private void drawClock(Canvas canvas) {

        int w = getMeasuredWidth();
        int h = getMeasuredHeight();

        float x = w / 2;
        float cellAngle = 360.0f / maxCount;

        canvas.save();

        switch (classStyle) {
            case CLASS_STYLE_CLOCK_CLEAR:
                canvas.rotate(cellAngle * current, w / 2, h / 2);
                break;
            case CLASS_STYLE_CLOCK:

            default:
                clockPaint.setColor(clockProgressColor);
                for (int i = 0; i < current; i++) {
                    canvas.drawLine(x, 0, x, clockLength, clockPaint);
                    canvas.rotate(cellAngle, w / 2, h / 2);
                }
        }

        int a = maxCount - current;
        clockPaint.setColor(clockDefaultColor);
        for (int i = 0; i < a; i++) {
            canvas.drawLine(x, 0, x, clockLength, clockPaint);
            canvas.rotate(cellAngle, w / 2, h / 2);
        }
        canvas.restore();

    }

    /**
     * @param canvas
     */
    private void drawDigit(Canvas canvas) {
        int w = getMeasuredWidth();
        int h = getMeasuredHeight();

        float y = getMeasuredHeight() / 2 + Math.abs((digitPaint.getFontMetrics().ascent + digitPaint.getFontMetrics().descent) / 2);
        if (isStart) {
            float x = (w - digitPaint.measureText((maxCount - current) + unitStr)) / 2;
            canvas.drawText((maxCount - current) + unitStr, x, y, digitPaint);
        } else {
            float x = (w - digitPaint.measureText(tipStr)) / 2;
            canvas.drawText(tipStr, x, y, digitPaint);
        }
    }

    /**
     * @param canvas
     */
    private void drawCircle(Canvas canvas) {
        int w = getMeasuredWidth();
        int h = getMeasuredHeight();


//        circlePaint.setColor(Color.GREEN);
//        canvas.drawRect(0,0,w,h,circlePaint);
        Paint.Style style = circlePaint.getStyle();

        circlePaint.setStyle(Paint.Style.STROKE);
        circlePaint.setColor(progressColor);
        canvas.save();
        float swepAngle = (float) (360.0 * current / maxCount);

        switch (classStyle) {
            case CLASS_STYLE_CIRCLE_CLEAR:

                break;
            default:
                canvas.drawArc(
                        circleRectf,
                        -90,
                        swepAngle,
                        false,
                        circlePaint);
        }


        circlePaint.setColor(backColor);
        canvas.drawArc(
                circleRectf,
                -90 + swepAngle,
                360 - swepAngle,
                false,
                circlePaint);

        circlePaint.setStyle(style);
        canvas.restore();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        switch (classStyle) {
            case CLASS_STYLE_CIRCLE:
            case CLASS_STYLE_CIRCLE_CLEAR:
                measuredCircle(widthMeasureSpec, heightMeasureSpec);
                break;
            case CLASS_STYLE_DIGIT:
                measuredDigit(widthMeasureSpec, heightMeasureSpec);
                break;
            case CLASS_STYLE_CLOCK:
            case CLASS_STYLE_CLOCK_CLEAR:
                measuredClock(widthMeasureSpec, heightMeasureSpec);
                break;
            case CLASS_STYLE_CIRCLE_DIGIT:
                measuredCircleDigit(widthMeasureSpec, heightMeasureSpec);
                break;
            case CLASS_STYLE_CLOCK_DIGIT:
                measuredClockDigit(widthMeasureSpec, heightMeasureSpec);
                break;
            default:
                super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    }

    /**
     * clock and digit
     *
     * @param widthMeasureSpec  widthMeasureSpec
     * @param heightMeasureSpec heightMeasureSpec
     */
    private void measuredClockDigit(int widthMeasureSpec, int heightMeasureSpec) {
        //measured width
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = 0;
        switch (widthMode) {
            case MeasureSpec.EXACTLY:
                widthSize = MeasureSpec.getSize(widthMeasureSpec);
                break;
            case MeasureSpec.AT_MOST:
                widthSize = (int) (clockLength * 4 + digitPaint.measureText(maxCount + unitStr + "  ") + getPaddingLeft() + getPaddingRight());
                break;
        }

        //measured height
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = 0;
        switch (heightMode) {
            case MeasureSpec.EXACTLY:
                heightSize = MeasureSpec.getSize(heightMeasureSpec);
                break;
            case MeasureSpec.AT_MOST:
                Paint.FontMetrics metrics = digitPaint.getFontMetrics();
                heightSize = (int) (metrics.bottom - metrics.top + getPaddingTop() + getPaddingBottom() + clockLength * 4);
                break;
        }

        if (widthSize > heightSize) {
            heightSize = widthSize;
        }
        setMeasuredDimension(widthSize, heightSize);
    }

    /**
     * circle and digit
     *
     * @param widthMeasureSpec  widthMeasureSpec
     * @param heightMeasureSpec heightMeasureSpec
     */
    private void measuredCircleDigit(int widthMeasureSpec, int heightMeasureSpec) {
        //measured width
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = 0;
        switch (widthMode) {
            case MeasureSpec.EXACTLY:
                widthSize = MeasureSpec.getSize(widthMeasureSpec);
                break;
            case MeasureSpec.AT_MOST:
                widthSize = (int) (circleWidth * 2 + digitPaint.measureText(maxCount + unitStr + "  ")) + getPaddingLeft() + getPaddingRight();
                break;
        }

        //measured height
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = 0;
        switch (heightMode) {
            case MeasureSpec.EXACTLY:
                heightSize = MeasureSpec.getSize(heightMeasureSpec);
                break;
            case MeasureSpec.AT_MOST:
                Paint.FontMetrics metrics = digitPaint.getFontMetrics();
                heightSize = (int) (metrics.bottom - metrics.top + getPaddingTop() + getPaddingBottom() + circleWidth * 2);
                break;
        }

        if (widthSize > heightSize) {
            heightSize = widthSize;
        }
        if (circleRectf == null) {
            circleRectf = new RectF(circleWidth / 2, circleWidth / 2, widthSize - circleWidth / 2, widthSize - circleWidth / 2);
        } else {
            circleRectf.set(circleWidth / 2, circleWidth / 2, widthSize - circleWidth / 2, widthSize - circleWidth / 2);
        }
        setMeasuredDimension(widthSize, heightSize);
    }

    private void measuredClock(int widthMeasureSpec, int heightMeasureSpec) {
        //measured width
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = 0;
        switch (widthMode) {
            case MeasureSpec.EXACTLY:
                widthSize = MeasureSpec.getSize(widthMeasureSpec);
                break;
            case MeasureSpec.AT_MOST:
                widthSize = (int) (clockLength * 4);
                break;
        }

        //measured height
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = 0;
        switch (heightMode) {
            case MeasureSpec.EXACTLY:
                heightSize = MeasureSpec.getSize(heightMeasureSpec);
                break;
            case MeasureSpec.AT_MOST:
                heightSize = (int) (clockLength * 4);
                break;
        }

        if (widthSize > heightSize) {
            heightSize = widthSize;
        }
        setMeasuredDimension(widthSize, heightSize);
    }

    /**
     * measured digit
     *
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     */
    private void measuredDigit(int widthMeasureSpec, int heightMeasureSpec) {
        //measured width
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = 0;
        switch (widthMode) {
            case MeasureSpec.EXACTLY:
                widthSize = MeasureSpec.getSize(widthMeasureSpec);
                break;
            case MeasureSpec.AT_MOST:
                widthSize = (int) digitPaint.measureText(maxCount + unitStr + "  ") + getPaddingLeft() + getPaddingRight();
                int tipWidth = (int) (digitPaint.measureText(tipStr + "  ") + getPaddingLeft() + getPaddingRight());
                if (tipWidth > widthSize) {
                    widthSize = tipWidth;
                }
                break;
        }

        //measured height
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = 0;
        switch (heightMode) {
            case MeasureSpec.EXACTLY:
                heightSize = MeasureSpec.getSize(heightMeasureSpec);
                break;
            case MeasureSpec.AT_MOST:
                Paint.FontMetrics metrics = digitPaint.getFontMetrics();
                heightSize = (int) (metrics.bottom - metrics.top + getPaddingTop() + getPaddingBottom());
                break;
        }

        setMeasuredDimension(widthSize, heightSize);
    }

    /**
     * Circle
     *
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     */
    private void measuredCircle(int widthMeasureSpec, int heightMeasureSpec) {
        //measured width
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = 0;
        switch (widthMode) {
            case MeasureSpec.EXACTLY:
                widthSize = MeasureSpec.getSize(widthMeasureSpec);
                break;
            case MeasureSpec.AT_MOST:
                widthSize = (int) (circleWidth * 2);
                break;
        }

        //measured height
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = 0;
        switch (heightMode) {
            case MeasureSpec.EXACTLY:
                heightSize = MeasureSpec.getSize(heightMeasureSpec);
                break;
            case MeasureSpec.AT_MOST:
                heightSize = (int) (circleWidth * 2);
                break;
        }

        if (widthSize > heightSize) {
            widthSize = heightSize;
        }
        if (circleRectf == null) {
            circleRectf = new RectF(circleWidth / 2, circleWidth / 2, widthSize - circleWidth / 2, widthSize - circleWidth / 2);
        } else {
            circleRectf.set(circleWidth / 2, circleWidth / 2, widthSize - circleWidth / 2, widthSize - circleWidth / 2);
        }
        setMeasuredDimension(widthSize, heightSize);
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        removeCallbacks(countRunnable);
    }

    public void start() {
        removeCallbacks(countRunnable);
        handler.sendEmptyMessage(0);
        postDelayed(countRunnable, 1000);
    }

    public void stop() {
        removeCallbacks(countRunnable);
        handler.sendEmptyMessage(1);
    }

    /**
     * 计数
     */
    private Runnable countRunnable = new Runnable() {
        @Override
        public void run() {

            current++;
            postInvalidate();
            if (current < maxCount) {//continue
                postDelayed(countRunnable, 1000);
            } else {//end
                handler.sendEmptyMessage(1);
            }

        }
    };

    public void setOnTimerListener(OnTimerListener onTimerListener) {
        this.onTimerListener = onTimerListener;
    }

    public int getClassStyle() {
        return classStyle;
    }

    public void setClassStyle(int classStyle) {
        this.classStyle = classStyle;
    }

    public int getMaxCount() {
        return maxCount;
    }

    public void setMaxCount(int maxCount) {
        this.maxCount = maxCount;
    }

    public int getCurrent() {
        return current;
    }

    public void setCurrent(int current) {
        this.current = current;
    }

    public float getCircleWidth() {
        return circleWidth;
    }

    public void setCircleWidth(float circleWidth) {
        this.circleWidth = circleWidth;
        circlePaint.setStrokeWidth(circleWidth);
    }

    public boolean isStart() {
        return isStart;
    }

    public int getProgressColor() {
        return progressColor;
    }

    public void setProgressColor(int progressColor) {
        this.progressColor = progressColor;
    }

    public int getBackColor() {
        return backColor;
    }

    public void setBackColor(int backColor) {
        this.backColor = backColor;
    }

    public String getUnitStr() {
        return unitStr;
    }

    public void setUnitStr(String unitStr) {
        this.unitStr = unitStr;
    }

    public float getDigitSize() {
        return digitSize;
    }

    public void setDigitSize(float digitSize) {
        this.digitSize = digitSize;
        digitPaint.setTextSize(digitSize);
    }

    public float getClockWidth() {
        return clockWidth;
    }

    public void setClockWidth(float clockWidth) {
        this.clockWidth = clockWidth;
        clockPaint.setStrokeWidth(clockWidth);
    }

    public float getClockLength() {
        return clockLength;
    }

    public void setClockLength(float clockLength) {
        this.clockLength = clockLength;
    }

    public int getClockDefaultColor() {
        return clockDefaultColor;
    }

    public void setClockDefaultColor(int clockDefaultColor) {
        this.clockDefaultColor = clockDefaultColor;
    }

    public int getClockProgressColor() {
        return clockProgressColor;
    }

    public void setClockProgressColor(int clockProgressColor) {
        this.clockProgressColor = clockProgressColor;
    }

    /**
     * timer callback
     */
    public interface OnTimerListener {
        /**
         * on start
         */
        public void onTimerStart();

        /**
         * on complete
         */
        public void onTimerComplete();
    }

    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case 0://start
                    isStart = true;
                    if (onTimerListener != null) {
                        onTimerListener.onTimerStart();
                    }
                    break;
                case 1://end
                    if (onTimerListener != null) {
                        onTimerListener.onTimerComplete();
                    }
                    current = 0;
                    isStart = false;
                    break;
            }
            invalidate();
        }
    };
}
